<template>
  <!-- Map容器 -->
  <div id="map" class="map__x" ref="mapCom"></div>
  <!-- 弹窗信息 -->
  <div ref="popup" class="popup" v-show="shopPopup">
    <div class="title">
      <h1>{{ PopupInfo.name }}</h1>
      <el-icon class="icon-close" @click="closePopup(overlayDig)"
        ><close-bold
      /></el-icon>
    </div>
    <div class="content">
      <div>经度</div>
      <div>纬度</div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted ,reactive} from "vue";
import { Map, View, Feature } from "ol";
import Tile from "ol/layer/Tile";
import XYZ from "ol/source/XYZ"; // 引入XYZ地图格式

import "ol/ol.css";
import { fromLonLat } from "ol/proj";
import { boundingExtent } from "ol/extent";
import { transformExtent } from "ol/proj";
import { transform } from "ol/proj";
import * as style from "ol/style";
import VectorSource from "ol/source/Vector";
import { Vector as VectorLayer } from "ol/layer";
import Point from "ol/geom/Point";
import Overlay from "ol/Overlay";
import GeoJSON from "ol/format/GeoJSON";
import SourceVector from "ol/source/Vector";
import { Draw, Modify } from "ol/interaction";
import { createRegularPolygon, createBox } from "ol/interaction/Draw";
import Circle from "ol/geom/Circle";
//导入抽离的事件方法
import {
  hideLayer,
  closePopup,
  CustomControl,
  zoomIn,
  addPointOverlay,
} from "./Map.js";
// 引入图标图片
import iconPng from "../../../assets/icons/sst1.png";
import QH from "./xl.json";
// 容器 ref
const mapCom = ref(null);
const map = ref(null); //地图实列
const pointInit = ref(null); // 标记点
const overlayDig = ref(null); // 弹窗
const popup = ref(null); // 弹窗容器
const shopPopup = ref(false); // 是否显示弹窗
const PopupInfo = reactive({
  name: "",
  remark: "",
  longitude: "",
  latitude: "",
});
const plotLayer = ref(null); //绘制图形的图层
const state = reactive({
  //绘制图形的 数据等配置
  tool: null,
  draw: null,
  modify: null,
  source: new VectorSource({
    wrapX: false, // 禁止横向无限重复（底图渲染的时候会横向无限重复），设置了这个属性，可以让绘制的图形不跟随底图横向无限重复
  }),
});
// 可视范围
const extent = boundingExtent([
  [107.14141846, 24.01887061], // 最左端 经纬度坐标
  [109.59136963, 22.15179558], // 最右端 经纬度坐标
]);

const initMap = (pointList) => {
  // 添加标记点用来显示摄像头
  addOverlay(pointList);
  plotLayer.value = addDrawLayer();
  // 地图实例
  map.value = new Map({
    target: "map", // 对应页面里 id 为 map 的元素
    layers: [
      // 图层 一个地图实列可以由多个图层组成
      // Tile 瓦片数据源 Image 整张图的数据源  Vector 矢量地图源
      new Tile({
        name: "defaultLayer",
        source: new XYZ({
          // 瓦片底图地址
          // url: " http://192.168.30.254:8080" + "/{z}/{x}/{y}.jpg",
          //测试
          url: "http://t0.tianditu.com/DataServer?T=img_w&tk=2a97e437df0cecf442afd180ad6aa7d2&x={x}&y={y}&l={z}",
        }),
      }),
      //测试
      new Tile({
        source: new XYZ({
          url: "http://t0.tianditu.com/DataServer?T=cia_w&tk=2a97e437df0cecf442afd180ad6aa7d2&x={x}&y={y}&l={z}",
        }),
      }),
      pointInit.value,
      plotLayer.value,
    ],
    // 地图视图 可以控制地图中心 缩放大小等
    view: new View({
      projection: "EPSG:3857", // 坐标系，有EPSG:4326和EPSG:3857
      center: fromLonLat([108.32, 22.82]), // 南宁
      extent: transformExtent(extent, "EPSG:4326", "EPSG:3857"), // 可视范围限制
      zoom: 12, // 地图缩放级别（打开页面时默认级别）
      minZoom: 8, // 地图缩放最小级别
      maxZoom: 18, // 地图缩放最大级别
    }),
  });
  // 点击事件
  mapClick();

  // 实例化自定义控件
  const customControl = new CustomControl();
  map.value.addControl(customControl);
  // 为自定义控件添加点击事件
  customControl.element.addEventListener("click", () => {
    hideLayer(pointInit);
  });
};
// 定位到某一个 位置
const toPoint = (longitude = 108.3114624, latitude = 22.82365602) => {
  //这里给动画设置一个初始值
  map.value.getView().animate({
    //将地理坐标转为投影坐标
    center: transform([longitude, latitude], "EPSG:4326", "EPSG:3857"), //将 4326转为 3857   将经纬度转为 莫托投影
    duration: 1000,
    zoom: 15,
  });
};

// 矢量图层添加方法 预想这个方法是在初始化地图的时候调用  要求后端传入 摄像头标记点的 经纬度数组
const addOverlay = (arrlist = []) => {
  // 创建矢量数据源，将图标特性添加进容器中
  const vectorSource = new VectorSource({});
  arrlist.forEach((item) => {
    // 创建图标特性
    const iconFeature = new Feature({
      geometry: new Point(fromLonLat([item.longitude, item.latitude])), // 图标位置
      name: item.name,
      longitude: item.longitude,
      latitude: item.latitude,
      remark: item.remark,
      //还可以添加其他属性
    });

    const iconStyle = new style.Style({
      image: new style.Icon({
        anchor: [0.1, 0.1], // 根据图标的大小，
        anchorXUnits: "pixels",
        anchorYUnits: "pixels",
        src: iconPng, // 或者 src: require('../../assets/images/icon.png')
      }),
    });

    // 把样式应用到图标上
    iconFeature.setStyle(iconStyle);

    vectorSource.addFeature(iconFeature);
  });
  //创建矢量图层
  pointInit.value = new VectorLayer({
    name: "pointInitLayer",
    properties: {
      name: "pointInitLayer",
    },
    source: vectorSource,
  });
};

//添加地图轮廓 矢量图层
const addoutline = (vectorJson, arrlist) => {
  const source = new SourceVector({
    features: new GeoJSON().readFeatures(vectorJson, {
      dataProjection: "EPSG:4326",
      featureProjection: "EPSG:3857",
      extractGeometryName: true,
    }),
  });
  const vectorLayer = new VectorLayer({
    source: source,
    properties: {
      name: "gaoJsonLayer",
    },
    name: "gaoJsonLayer",
    style: new style.Style({
      stroke: new style.Stroke({
        color: "rgba(0, 0, 0, 1)", // 设置轮廓颜色
        width: 2, // 设置轮廓宽度
      }),
      fill: new style.Fill({
        color: "rgba(255, 255, 255, 0)", // 设置填充颜色为透明
      }),
    }),
  });
  map.value.addLayer(vectorLayer);
  // zoomIn(map, 10);
  // 获取矢量图层中所有要素的扩展范围
  const extent = source.getExtent();
  // 设置地图视图的中心点和缩放级别
  map.value.getView().fit(extent, {
    padding: [100, 100, 100, 100], // 设置内边距，避免地图边缘被裁剪
    maxZoom: 18, // 设置最大缩放级别
    zoomDuration: 1000, // 设置缩放动画的持续时间（毫秒）
  });
  addPointOverlay(map, arrlist);
  hideLayer(pointInit, "off");
};

//添加多一个图层用来做绘画
const addDrawLayer = () => {
  const vector = new VectorLayer({
    source: state.source,
    name: "DrawLayer",
    properties: {
      name: "DrawLayer",
    },
    style: new style.Style({
      fill: new style.Fill({
        color: "rgba(255, 255, 255, 0.2)",
      }),
      stroke: new style.Stroke({
        color: "#ffcc33",
        width: 2,
      }),
      image: new style.Circle({
        radius: 7,
        fill: new style.Fill({
          color: "#ffcc33",
        }),
      }),
    }),
  });
  return vector;
};
const changeDrawTool = (tool) => {
  console.log("🚀 ~ changeDrawTool ~ tool:", tool);
  state.tool = tool;
  addInteraction();
};
// 开始绘制
const addInteraction = () => {
  let geometryFunction;
  let type = state.tool;
  if (state.draw !== null) {
    map.value.removeInteraction(state.draw);
  }

  if (state.tool !== "None" && state.tool !== "empty") {
    if (state.tool === "Square") {
      type = "Circle";
      // 方形
      geometryFunction = createRegularPolygon(4);
    } else if (state.tool === "Rectangle") {
      type = "Circle";
      // 矩形
      geometryFunction = createBox();
    }
    state.draw = new Draw({
      source: state.source,
      type: type,
      geometryFunction,
    });
    map.value.addInteraction(state.draw);
    // 修改绘制完的图形
    state.modify = new Modify({ source: state.source, geometryFunction });
    map.value.addInteraction(state.modify);
  } else if (state.tool === "empty") {
    if (state.source) {
      state.source.clear();
    }
  } else {
  }

  // ModifyIconEnd();
};

// 监听 state.source的点击事件
state.source.on("addfeature", function (event) {
  const feature = event.feature; // 获取新添加的 Feature
  const geometry = feature.getGeometry(); // 获取几何对象

  if (geometry instanceof Circle) {
    console.log("这是一个圆！");

    // 获取圆心坐标和半径
    const center = geometry.getCenter();
    const radius = geometry.getRadius();

    console.log("圆心:", center);
    console.log("半径:", radius);
  }
  let features = state.source.getFeatures();
  console.log("🚀 ~ features:", features);
  let jsonObj = new GeoJSON().writeFeatures(features, {
    featureProjection: "EPSG:3857", // 地图投影坐标系
    dataProjection: "EPSG:4326", // 导出数据的投影坐标系
  });
  console.log("🚀 ~ features:", JSON.parse(jsonObj));
});

// 添加地图点击事件
const mapClick = () => {
  // 弹窗 用来控制点击摄像头后出现的东西
  overlayDig.value = new Overlay({
    element: popup.value, // 弹窗标签，在html里
    // autoPan: true, // 如果弹窗在底图边缘时，底图会移动
    autoPanAnimation: {
      // 底图移动动画
      duration: 250,
    },
    positioning: "bottom-center",
    stopEvent: false,
    offset: [0, -50],
  });
  map.value.addOverlay(overlayDig.value);
  map.value.on("singleclick", (evt) => {
    let clickedLayer = null; // 用于存储点击的图层
    // 判断是不是点击的 feature标记点
    const feature = map.value.forEachFeatureAtPixel(
      evt.pixel,
      function (feature, layer) {
        clickedLayer = layer;
        return feature;
      }
    );

    // 判断如果有图层时显示弹窗否则不显示
    if (feature) {
      // zoomIn();
      if (clickedLayer) {
        // 如果需要根据不同的图层执行不同的逻辑，可以在下面添加条件判断
        const layerName = clickedLayer.get("name");
        // 这里添加了两个图层的名字 都是指定只有点击摄像头的名字 才可以出现弹窗
        if (layerName === "pointInitLayer" || layerName === "pointLayer") {
          shopPopup.value = true;
          overlayDig.value.setPosition(evt.coordinate);
          // 直接解构并赋值
          const { name, remark, longitude, latitude } = feature.values_;
          Object.assign(PopupInfo, { name, remark, longitude, latitude });
        } else {
          shopPopup.value = false;
        }
      }
    } else {
      shopPopup.value = false;
    }
  });
};

// 抽出去的事件方法
// //隐藏摄像头 标记
// const hideLayer = () => {
//   if (pointInit.value) {
//     const currentVisibility = pointInit.value.getVisible();
//     pointInit.value.setVisible(!currentVisibility);
//   }
// };
// 关闭弹窗
// const closePopup = () => {
//   overlayDig.value.setPosition(undefined);
// };
//动画缩放功能 本来是想和 摄像头点击后做一个zoom 效果 但是那个 定位会不准 不想调整了 就不做了
// const zoomIn = (targetZoom) => {
//   // 放大地图到指定的缩放级别

//   map.value.getView().animate(
//     {
//       zoom: targetZoom,
//       duration: 500, // 动画持续时间（毫秒）
//     },
//     () => {
//       console.log("动画完成");
//       // 这里可以执行任何需要在动画完成后进行的操作
//     }
//   );
// };
onMounted(() => {
  // initMap(); // 初始化地图
});
// 暴露方法给父组件使用
defineExpose({
  toPoint,
  initMap,
  addoutline,
  changeDrawTool,
});
</script>

<style lang="scss" scoped>
.map__x {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
}
.popup {
  width: 300px;
  height: 100px;
  background: #fff;
  position: absolute;
  top: -115px;
  left: -150px;
  box-sizing: border-box;
  border-radius: 10px;

  &::after {
    content: "";
    display: block;
    position: absolute;
    width: 20px;
    height: 20px;
    background: #fff;
    bottom: -10px;
    left: 50%;
    transform: translateX(-50%) rotate(45deg);
  }

  .icon-close {
    position: absolute;
    top: 0px;
    right: 8px;
  }

  .title {
    text-align: center;
    background-color: #e4e7ed;
    border-top-right-radius: 10px;
    border-top-left-radius: 10px;
  }

  .content {
    margin-top: 5px;
    line-height: 26px;
    font-size: 14px;
    padding-left: 10px;
  }
}
</style>
